package config

import (
	"fmt"
	"io/ioutil"
	"net"
	"os"

	"github.com/spf13/viper"
	"gopkg.in/yaml.v2"
)

var (
	Root = ""
)

var Config config

type config struct {
	Version string `yaml:"version"`
	ApiSix  struct {
		Address string `yaml:"address"`
	}
	Log struct {
		StorageLocation       string   `yaml:"storageLocation"`
		RotationTime          int      `yaml:"rotationTime"`
		RemainRotationCount   uint     `yaml:"remainRotationCount"`
		RemainLogLevel        uint     `yaml:"remainLogLevel"`
		ElasticSearchSwitch   bool     `yaml:"elasticSearchSwitch"`
		ElasticSearchAddr     []string `yaml:"elasticSearchAddr"`
		ElasticSearchUser     string   `yaml:"elasticSearchUser"`
		ElasticSearchPassword string   `yaml:"elasticSearchPassword"`
	}
	Redis struct {
		DBAddress     string `yaml:"dbAddress"`
		DBMaxIdle     int    `yaml:"dbMaxIdle"`
		DBMaxActive   int    `yaml:"dbMaxActive"`
		DBIdleTimeout int    `yaml:"dbIdleTimeout"`
		DBPassWord    string `yaml:"dbPassWord"`
		Database      int    `yaml:"database"`
		DbTxt2img     int    `yaml:"dbTxt2img"`
		CountStyleNum int    `yaml:"countStyleNum"`
		SectionQg     int    `yaml:"sectionQg"`
	}
	Mysql struct {
		DBAddress      []string `yaml:"dbMysqlAddress"`
		DBUserName     []string `yaml:"dbMysqlUserName"`
		DBPassword     []string `yaml:"dbMysqlPassword"`
		DBDatabaseName []string `yaml:"dbMysqlDatabaseName"`
		DBMaxOpenConns int      `yaml:"dbMaxOpenConns"`
		DBMaxIdleConns int      `yaml:"dbMaxIdleConns"`
		DBMaxLifeTime  int      `yaml:"dbMaxLifeTime"`
	}
	App struct {
		JwtSignKey string `yaml:"jwtSignKey"`
		JwtSignTTL int    `yaml:"jwtSignTTL"`
		JwtIssuer  string `yaml:"jwtIssuer"`
		ServerIP   string `yaml:"serverIp"`
	}

	SnowFlake struct {
		SnowFlakeMachineId int64 `yaml:"SnowFlakeMachineId"`
	}

	Credential struct {
		Ali struct {
			RegionID        string `yml:"regionid"`
			AccessKeyID     string `yml:"accesskeyid"`
			AccessKeySecret string `yml:"accesskeysecret"`
			OssEndpoint     string `yml:"ossendpoint"`
			Bucket          string `yml:"bucket"`
			FinalHost       string `yml:"finalhost"`
		}
		Qiniu struct {
			AccessKeyID     string `yml:"accesskeyid"`
			AccessKeySecret string `yml:"accesskeysecret"`
			Bucket          string `yml:"bucket"`
			FinalHost       string `yml:"finalhost"`
		}
	}
	Mail struct {
		Title             string   `yml:"title"`
		Sender            string   `yml:"sender"`
		AuthorizationCode string   `yml:"authorizationcode"`
		SmtpAddr          string   `yml:"smtpaddr"`
		SmtpPort          int      `yml:"smtpport"`
		AdminNotify       []string `yml:"adminnotify"`
	}

	Elk struct {
		ElasticSearchAddr []string `yml:"elasticsearchaddr"`
		MovieIndexName    string   `yml:"movieindexname"` //当前存储的索引
	}
	AliSMSVerify struct {
		AccessKeyID                  string   `yaml:"accessKeyId"`
		AccessKeySecret              string   `yaml:"accessKeySecret"`
		SignName                     string   `yaml:"signName"`
		VerificationCodeTemplateCode string   `yaml:"verificationCodeTemplateCode"`
		SuperCode                    string   `yaml:"superCode"`
		CodeTTL                      int      `yaml:"codeTTL"`
		UseSupperPhone               []string `yaml:"useSupperPhone"`
		SendMaxLimit                 int      `yaml:"sendmaxlimit"`
	}
	Gpt struct {
		FreeGptUrl string `ymal:"freegpturl"`
		Openai     string `ymal:"openais"`
		Claudeai   string `ymal:"claudeai"`
	}
	Stablediffusion struct {
		Apiurl []string `ymal:"apiurl"`
	}
	Wx struct {
		Appid  string `yml:"appid"`
		Secret string `yml:"secret"`
	}
}

func init() {
	dir, _ := os.Getwd()
	Root = dir
	cfgFile := Root + "/config/config.yaml"
	viper.SetConfigFile(cfgFile) // 指定配置文件路径
	err := viper.ReadInConfig()  // 查找并读取配置文件
	if err != nil {
		panic(fmt.Errorf("fatal error config file: %s", err))
	}
	toConfig(cfgFile)
	initServerIP()
}

func toConfig(filename string) {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		panic(err.Error())
	}
	if err = yaml.Unmarshal(bytes, &Config); err != nil {
		panic(err.Error())
	}
}

func initServerIP() {
	// fixme In the configuration file, ip takes precedence, if not, get the valid network card ip of the machine
	if Config.App.ServerIP == "" {
		// see https://gist.github.com/jniltinho/9787946#gistcomment-3019898
		conn, err := net.Dial("udp", "8.8.8.8:80")
		if err != nil {
			panic(err.Error())
		}
		defer conn.Close()
		localAddr := conn.LocalAddr().(*net.UDPAddr)
		Config.App.ServerIP = localAddr.IP.String()
	}
}
